package com.tansun.easycare.rule.referencedata.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.tansun.easycare.rule.common.DataCache;
import com.tansun.easycare.rule.common.DataSetTreeVo;
import com.tansun.easycare.rule.common.entity.RuleBaseEntity;
import com.tansun.easycare.rule.common.service.DataBomService;
import com.tansun.easycare.rule.common.service.impl.RuleBaseServiceImpl;
import com.tansun.easycare.rule.datamodel.entity.RuleDataparams;
import com.tansun.easycare.rule.datamodel.service.RuleDataparamsService;
import com.tansun.easycare.rule.exception.BizException;
import com.tansun.easycare.rule.referencedata.dao.RuleReferenceDataDao;
import com.tansun.easycare.rule.referencedata.entity.RefFuncParam;
import com.tansun.easycare.rule.referencedata.entity.RuleReferenceData;
import com.tansun.easycare.rule.referencedata.service.RefFuncParamService;
import com.tansun.easycare.rule.referencedata.service.RuleReferenceDataService;
import com.tansun.easycare.rule.ruleflow.entity.RuleFlowRects;
import com.tansun.easycare.rule.rulemange.entity.RuleManage;
import com.tansun.easycare.rule.rulemange.service.RuleManageService;
import com.tansun.easycare.rule.ruleversion.service.RuleVersioninfoService;
import com.tansun.easycare.rule.table.entity.RuleDecisiontableDetail;
import com.tansun.rule.common.RuleModelTypeEnum;
import com.tansun.rule.utils.StringUtils;

@Service
public class RuleReferenceDataServiceImpl extends RuleBaseServiceImpl<RuleReferenceDataDao, RuleReferenceData> implements RuleReferenceDataService {

	@Autowired
	private  DataBomService  dataBomService;
    @Autowired
    private RuleVersioninfoService ruleVersioninfoService;
    @Autowired
    private RuleManageService ruleManageService;
	@Autowired
	private  RuleDataparamsService  ruleDataparamsService;
	
	@Autowired
	private RefFuncParamService refFuncParamService;
	
    @Override
    public void collectTableDetail(RuleDecisiontableDetail decisiontableDetail, Map<String, RuleReferenceData> map, RuleManage ruleManage) throws BizException {
        //变量为空字符串，跳过
    	if(StringUtils.isEmpty(decisiontableDetail.getNameen())) {
        	return;
        }
    	RuleReferenceData ruleReferenceData = new RuleReferenceData();
        String key = decisiontableDetail.getClassName() + "_" + decisiontableDetail.getNameen() + "_" + decisiontableDetail.getContentType();
        try {
        	ConvertUtils.register(new DateConverter(null), java.util.Date.class);
            BeanUtils.copyProperties(ruleReferenceData, decisiontableDetail);
            ruleReferenceData.setId(null);
            ruleReferenceData.setCode(ruleManage.getCode());
            ruleReferenceData.setProjectCode(ruleManage.getProjectCode());
            ruleReferenceData.setModelType(ruleManage.getModelType());
            ruleReferenceData.setVersion(ruleManage.getVersion());
            ruleReferenceData.setManageId(ruleManage.getId());
            if (RuleModelTypeEnum.DecisionTable.getCode().equals(decisiontableDetail.getModelType())
                    && decisiontableDetail.getRowNo() == 0) {
                ruleReferenceData.setSeq(-1);
            } else {
                ruleReferenceData.setSeq(decisiontableDetail.getColumnNo());
            }
            ruleReferenceData.setId(null);
            ruleReferenceData.setIsNewRecord(false);
            map.put(key, ruleReferenceData);
            if("true".equals(decisiontableDetail.getIsDerives())){
            	this.collectFromFormula(decisiontableDetail.getControlValue(), ruleManage, map);
            }
        } catch (Exception e) {
            throw new BizException(e, "E-000000");
        }
    }

    @Override
    public void collectCommonData(@SuppressWarnings("rawtypes") RuleBaseEntity dataEntity, String key, String contentType, RuleManage ruleManage, Map<String, RuleReferenceData> map) throws BizException {
        RuleReferenceData ruleReferenceData = new RuleReferenceData();
        try {
        	ConvertUtils.register(new DateConverter(null), java.util.Date.class);
            BeanUtils.copyProperties(ruleReferenceData, dataEntity);
            ruleReferenceData.setId(null);
            ruleReferenceData.setManageId(ruleManage.getId());
            ruleReferenceData.setProjectCode(ruleManage.getProjectCode());
            ruleReferenceData.setCode(ruleManage.getCode());
            ruleReferenceData.setVersion(ruleManage.getVersion());
            ruleReferenceData.setContentType(contentType);
            ruleReferenceData.setModelType(ruleManage.getModelType());
            ruleReferenceData.setIsNewRecord(false);
            if (ruleReferenceData.getSeq() == null) {
                ruleReferenceData.setSeq(0);
            }
            map.put(key, ruleReferenceData);
        } catch (Exception e) {
            throw new BizException(e, "E-000000");
        }
    }

    @Override
    public void collectCommonData(@SuppressWarnings("rawtypes") RuleReferenceData ruleReferenceData, String key, String contentType, RuleManage ruleManage, Map<String, RuleReferenceData> map) throws BizException {

        try {
            ruleReferenceData.setId(null);
            ruleReferenceData.setManageId(ruleManage.getId());
            ruleReferenceData.setProjectCode(ruleManage.getProjectCode());
            ruleReferenceData.setCode(ruleManage.getCode());
            ruleReferenceData.setVersion(ruleManage.getVersion());
            ruleReferenceData.setContentType(contentType);
            ruleReferenceData.setModelType(ruleManage.getModelType());
            ruleReferenceData.setIsNewRecord(false);
            if (ruleReferenceData.getSeq() == null) {
                ruleReferenceData.setSeq(0);
            }
            map.put(key, ruleReferenceData);
        } catch (Exception e) {
            throw new BizException(e, "E-000000");
        }
    }
    
    public void collectFromMap(Map<String, String> dataMap, String key, String contentType, RuleManage ruleManage, Map<String, RuleReferenceData> map) throws BizException {

        try {
        	RuleReferenceData referenceData = new RuleReferenceData();
        	referenceData.setClassName(dataMap.get("className"));
        	referenceData.setNamecn(dataMap.get("nameCN"));
        	referenceData.setNameen(dataMap.get("nameEN"));
        	referenceData.setDataType(dataMap.get("dataType"));
        	referenceData.setDefaultValue(dataMap.get("defaultValue"));
        	referenceData.setDomain(dataMap.get("domain"));
        	referenceData.setPattern(dataMap.get("pattern"));
        	referenceData.setIsCollections(dataMap.get("isCollections"));
        	referenceData.setId(null);
        	referenceData.setManageId(ruleManage.getId());
        	referenceData.setProjectCode(ruleManage.getProjectCode());
        	referenceData.setCode(ruleManage.getCode());
        	referenceData.setVersion(ruleManage.getVersion());
        	referenceData.setContentType(contentType);
        	referenceData.setModelType(ruleManage.getModelType());
        	referenceData.setIsNewRecord(false);
            if (referenceData.getSeq() == null) {
            	referenceData.setSeq(0);
            }
            map.put(key, referenceData);
        } catch (Exception e) {
            throw new BizException(e, "E-000000");
        }
    }
    @Override
    public void saveReferenceData(Map<String, RuleReferenceData> map) throws BizException {
        if (map.isEmpty())
            return;
        List<RuleReferenceData> list = new ArrayList();
        list.addAll(map.values());
        super.insertBatch(list);

    }
    
    @Override
    public void saveReferenceDataFuncRef(List<RuleDataparams> ruleParamdatas,RuleManage ruleManage) throws BizException{
    	if(ruleParamdatas!=null && ruleParamdatas.size()>0) {
            Map<String,RuleDataparams> className2RDP = this.ruleDataparamsService.findParamsKeyClassNameDotNameByProjectCode(ruleManage.getProjectCode());
            
    		List<RefFuncParam> list = new ArrayList<RefFuncParam>();
    		Set<String> keyset = new HashSet<String>();//去重
    		for(RuleDataparams rdp:ruleParamdatas) {
    			String key = rdp.getClassName() + "."+rdp.getName();
    			if( className2RDP.containsKey(key) && !keyset.contains(key)) {
					keyset.add(key);
					String rulefuncid = className2RDP.get(key).getId();
   				 	list.add(new RefFuncParam(ruleManage,rulefuncid));
    			}
    		}
    		this.refFuncParamService.insertBatch(list);
    		DataCache.refFuncParamChange(ruleManage.getProjectCode());
    	}
    }


    @Override
    public Collection<RuleReferenceData> reDataModeRef(List<RuleReferenceData> list) {
        Map<String, RuleReferenceData> map = new HashMap<>();
        String key = null;
        for (RuleReferenceData referenceData : list) {
            key = referenceData.getClassName() + "_" + referenceData.getNameen() + "_" + referenceData.getContentType();
            map.put(key, referenceData);
        }
        return map.values();
    }

    /**
     * 根据组件的ruleManage查找引用函数变量的关联数据
     */
    public void findFuncReferenceDataList(RuleManage ruleManage, Collection<RuleReferenceData> refList) throws BizException{
	    RefFuncParam refFuncParam = new RefFuncParam(ruleManage,null);
	    Collection<RefFuncParam> rfpList = refFuncParamService.findList(refFuncParam);
	    if(rfpList!=null && rfpList.size()>0) {
	    	//已缓存
		    Collection<RuleReferenceData> funclist = refFuncParamService.findAllFuncReferenceDataListByprojectCode(ruleManage.getProjectCode());
		    
		    //去重，并获取函数变量id
		    Set<String> paramids = new HashSet<String>();
	    	for(RefFuncParam rfp:rfpList) {
	    		paramids.add(rfp.getFuncparamId());
	    	}
	    	//递归查找函数变量的引用变量
	    	Map<String,RuleReferenceData> map = new HashMap<String,RuleReferenceData>();
	    	findReferenceDataList(paramids,funclist, map);
		    refList.addAll(map.values());
	    }
    }
    /**
     * 根据 函数变量查找其应用的函数变量
     */
    public void findFuncReferenceDataList(String projectCode,String className,String name, Collection<RuleReferenceData> refList) throws BizException{    	
        Map<String,RuleDataparams> className2RDP = this.ruleDataparamsService.findParamsKeyClassNameDotNameByProjectCode(projectCode);
        
    	String key = className + "." + name;
    	RuleDataparams rdp = className2RDP.get(key);

    	Set<String> paramids = new HashSet<String>();
    	paramids.add(rdp.getId());
    	//已缓存
    	Collection<RuleReferenceData> funclist = refFuncParamService.findAllFuncReferenceDataListByprojectCode(projectCode);
    	
	    //递归查找函数变量的引用变量
	    Map<String,RuleReferenceData> contains = new HashMap<String,RuleReferenceData>();
	    findReferenceDataList(paramids,funclist, contains);
	    refList.addAll(contains.values());
    }
    /**
     * 递归查找函数变量的引用变量
     * @param paramids
     * @param funclist
     * @param map
     */
    public void findReferenceDataList(Set<String> paramids,Collection<RuleReferenceData> funclist,Map<String,RuleReferenceData> map) {
    	Set<String> newParamids = new HashSet<String>();
    	for(String paramid:paramids) {
    		for(RuleReferenceData data:funclist) {
    			String key = data.getClassName()+"."+data.getNamecn();
    	    	if(paramid.equals(data.getManageId())&&!map.containsKey(key)) {
    	    		map.put(key, data);
	    			if("1".equals(data.getIsFuncParam())) {
	    				newParamids.add(data.getParamId());
	    			}
    	    	}
			}
    	}
    	if(newParamids.size()>0) {
    		findReferenceDataList(newParamids, funclist, map);
    	}
    }
    
    public void findFuncReferenceDataList(RuleManage ruleManage, Collection<RuleReferenceData> refList,String type) throws BizException{
    	RefFuncParam refFuncParam = new RefFuncParam(ruleManage,null);
	    Collection<RuleReferenceData> fristRefData = refFuncParamService.findReferenceDataList(refFuncParam);
	    if(fristRefData!=null && fristRefData.size()>0) {
	    	//已缓存
	    	Collection<RuleReferenceData> funclist = refFuncParamService.findAllFuncReferenceDataListByprojectCode(ruleManage.getProjectCode());

		    Set<String> paramids = new HashSet<String>();
		    Map<String,RuleReferenceData> map = new HashMap<String,RuleReferenceData>();
	    	for(RuleReferenceData rrdata:fristRefData) {
	    		String key = rrdata.getClassName()+"."+rrdata.getNamecn();
	    		if(!map.containsKey(key)&&type.equals(rrdata.getContentType())) {
	    			map.put(key, rrdata);
	    			paramids.add(rrdata.getParamId());
	    		}
	    	}
		    findReferenceDataList(paramids,funclist, map);
		    refList.addAll(map.values());
	    }
    }
    
    //递归查找
    public void findReferenceDataList(String projectCode, String code, String type, String version, String contentType, Collection<RuleReferenceData> refList,List<String> listFlag){
    	if(listFlag==null) {
    		//防止重复，死循环
    		listFlag = new ArrayList<String>();
    	}
    	//存在标志位，就返回
    	if(listFlag.contains(code)) {
    		return;
    	}else {
    		listFlag.add(code);
    	}
    	RuleReferenceData ruleReferenceData = new RuleReferenceData();
        ruleReferenceData.setProjectCode(projectCode);
        ruleReferenceData.setCode(code);
        ruleReferenceData.setVersion(version);
		 if(!StringUtils.isEmpty(contentType))ruleReferenceData.setContentType(contentType);
        //ruleReferenceData.setModelType(type);
        //查询本身关联数据
        Collection<RuleReferenceData> baseList = this.findReferenceDataList(ruleReferenceData);
        refList.addAll(baseList);
        //if (RuleModelTypeEnum.DecisionTree.code.equals(type)) {
	        RuleManage search = new RuleManage();
	        search.setProjectCode(projectCode);
	        search.setCode(code);
	        search.setVersion(version);
	        List<RuleManage> rmList = this.ruleManageService.findListByRefManage(search);
        	if (rmList !=null && rmList.size()>0) {
            	for(RuleManage rm:rmList) {
                    ruleReferenceData.setProjectCode(projectCode);
                    ruleReferenceData.setCode(rm.getCode());
                    ruleReferenceData.setVersion(rm.getActiveVersion());
                    this.findReferenceDataList(projectCode,rm.getCode(),rm.getModelType(),rm.getActiveVersion(),null,refList,listFlag);
            	}
        	}
       // }
    }

    @Override
    public Collection<RuleReferenceData> findReferenceDataList(RuleReferenceData referenceData) {
        return this.dao.findReferenceDataList(referenceData);
    }
    
	@Override
	public void collectFromFormula(String formula, RuleManage ruleManage, Map<String, RuleReferenceData> map)
			throws BizException {
		if(StringUtils.isEmpty(formula) || !formula.contains("#{"))
			return ;

		Map<String,RuleDataparams> dstMap = new HashMap<String,RuleDataparams>();
		List<DataSetTreeVo> resultList = dataBomService.findBomListByProjCode(ruleManage.getProjectCode());//已缓存
		for (DataSetTreeVo dataSetTreeVo : resultList) {
			for (DataSetTreeVo child : dataSetTreeVo.getChildren()){
				RuleDataparams param = child.getParam();
				param.setClassName(dataSetTreeVo.getNameEN());
				dstMap.put(child.getParam().getId(), param);
			}
		}
		
		List<String> idList = new ArrayList<String>();
		String reg = "#\\{{1}([0-9a-zA-Z\\-]+)\\}";
		Pattern pattern = Pattern.compile(reg);
		Matcher matcher = pattern.matcher(formula);
		String group = new String();
		while (matcher.find()) {
			group = matcher.group(1);
			idList.add(group);
		}
		
		for (String string : idList) {
			if(dstMap.containsKey(string)){
				RuleDataparams dp = dstMap.get(string);
				RuleReferenceData referenceData = new RuleReferenceData();
	        	referenceData.setClassName(dp.getClassName());
	        	referenceData.setNamecn(dp.getChzn());
	        	referenceData.setNameen(dp.getName());
	        	referenceData.setDataType(dp.getType());
	        	referenceData.setDefaultValue(dp.getDefaultValue());
	        	referenceData.setDomain(dp.getDomain());
	        	referenceData.setPattern(dp.getPattern());
	        	referenceData.setIsCollections(dp.getIsCollections());
	        	referenceData.setManageId(ruleManage.getId());
	        	referenceData.setProjectCode(ruleManage.getProjectCode());
	        	referenceData.setCode(ruleManage.getCode());
	        	referenceData.setVersion(ruleManage.getVersion());
	        	referenceData.setContentType("in");
	        	referenceData.setModelType(ruleManage.getModelType());
	        	referenceData.setIsNewRecord(false);
	            referenceData.setSeq(0);
	            String key = dp.getClassName()+"_"+dp.getName()+"_in";
	            map.put(key, referenceData);
			}
		}
	}
	
	/**
	 * 关联数据复制
	 * @param ruleManageOld
	 * @param ruleManageNew
	 */
	public void copyReferenceData(RuleManage ruleManageOld,RuleManage ruleManageNew) {
		Collection<RuleReferenceData> list = new ArrayList<RuleReferenceData>();
		this.findReferenceDataList(ruleManageOld.getProjectCode(), ruleManageOld.getCode(), ruleManageOld.getModelType(), ruleManageOld.getVersion(), null, list, null);
		this.findFuncReferenceDataList(ruleManageOld, list);
		for(RuleReferenceData rd:list) {
			rd.setId(null);
			rd.setCode(ruleManageNew.getCode());
			rd.setVersion(ruleManageNew.getVersion());
			rd.setManageId(ruleManageNew.getId());
			rd.setModelType(ruleManageNew.getModelType());
			rd.setProjectCode(ruleManageNew.getProjectCode());
		}
		this.insertBatch((ArrayList<RuleReferenceData>)list);
	}
	
	/*判断是否被引用*/
	public List<RuleReferenceData>  findReferenceParamList(RuleReferenceData referenceData){
		return this.dao.findReferenceParamList(referenceData);
	}

	@Override
	public Collection<RuleReferenceData> findReferenceChampionList(RuleFlowRects flowRectsInfo) {
		return this.dao.findReferenceChampionList(flowRectsInfo);
	}

	@Override
	public List<RuleReferenceData> findModelReferenceList(Map<String, Object> map) {
		// TODO Auto-generated method stub
		return this.dao.findModelReferenceList(map);
	}

	@Override
	public void deleteByManage(RuleReferenceData arg0) {
		this.dao.deleteByManage(arg0);
	}
	
	@Override
	public void deleteByMutilVersion(RuleManage ruleManage, List<String> versions){
		if(versions!=null&&versions.size()>0) {
			Map<String,Object> map = new HashMap<String,Object>();
			map.put("projectCode", ruleManage.getProjectCode());
			map.put("manageId", ruleManage.getId());
			map.put("versions", versions);
			this.dao.deleteByMutilVersion(map);
		}
	}

	@Override
	public List<RuleReferenceData> findReferenceModelList(RuleReferenceData referenceData) {
		// TODO Auto-generated method stub
		return  this.dao.findReferenceModelList(referenceData);
	}
}
